package com.distribution.system.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.distribution.common.core.domain.entity.SysUser;
import com.distribution.common.exception.ServiceException;
import com.distribution.system.config.FuluConfig;
import com.distribution.system.domain.entity.*;
import com.distribution.system.mapper.FuluUploadPlanMapper;
import com.distribution.system.mapper.SysUserMapper;
import com.distribution.system.service.*;
import com.distribution.system.utils.DateUtil;
import com.distribution.system.utils.http.HttpRequestUtils;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * (CmccDaCommissionReflection)表服务实现类
 *
 * @author
 * @since 2023-05-21 20:06:19

 * @module
 */
@Service("fuluUploadPlanService")
@Slf4j
public class FuluUploadPlanServiceImpl extends ServiceImpl<FuluUploadPlanMapper, FuluUploadPlan> implements FuluUploadPlanService {


    @Resource
    FuluConfig fuluConfig;

    @Resource
    FuluUploadPeopleService fuluUploadPeopleService;

    @Resource
    FuluUploadEvidenceService fuluUploadEvidenceService;

    @Resource
    CmccDaCommissionReflectionService cmccDaCommissionReflectionService;

    @Resource
    SysUserMapper sysUserMapper;
    @Resource
    CmccDaOrderService cmccDaOrderService;

    @Value("${gzpt.appId}")
    private String gzptAppId;

    @Override
    public  List<Object> queryPayMethod() {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("taskNo",fuluConfig.getTaskNo());
        String param = paramPackage(paramsMap);
        String res = null;
        try {
            res = HttpRequestUtils.sendPost(fuluConfig.getAddress() + fuluConfig.getQueryPayMethod(), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        Integer code = jsonObject.getInteger("code");
        if (code != 0) {
            throw new ServiceException(jsonObject.getString("msg"));
        } else {
            JSONObject data = jsonObject.getJSONObject("data");
            JSONArray grantTypes = data.getJSONArray("grantTypes");
            return grantTypes.stream().filter(a -> !a.equals("银行卡")).collect(Collectors.toList());
        }
    }

    @Override
    public FuluUploadPlan uploadPlan(FuluUploadPlan fuluUploadPlan) {
        Map<String, Object> paramsMap = new HashMap<>(16);
        paramsMap.put("accountNumber",fuluUploadPlan.getAccountNumber());
        paramsMap.put("afterTaxAmount",fuluUploadPlan.getAfterTaxAmount());
        paramsMap.put("grantType",fuluUploadPlan.getGrantType());
        paramsMap.put("idCard",fuluUploadPlan.getIdCard());
        paramsMap.put("mobile",fuluUploadPlan.getMobile());
        paramsMap.put("outBizNo",generate32BitUUID());
        paramsMap.put("taskNo",fuluConfig.getTaskNo());
        paramsMap.put("remark",fuluUploadPlan.getRemark());
        paramsMap.put("userName",fuluUploadPlan.getUserName());
        if ("微信支付".equals(fuluUploadPlan.getGrantType())) {
            paramsMap.put("appId",gzptAppId);
            fuluUploadPlan.setAppId(gzptAppId);
        }
        fuluUploadPlan.setOutBizNo(String.valueOf(paramsMap.get("outBizNo")));
        fuluUploadPlan.setTaskNo(String.valueOf(paramsMap.get("taskNo")));
        String param = paramPackage(paramsMap);
        String res = null;
        try {
            res = HttpRequestUtils.sendPost(fuluConfig.getAddress() + fuluConfig.getUploadPlan(), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        Integer code = jsonObject.getInteger("code");
        if (code != 0) {
            throw new ServiceException(jsonObject.getString("msg"));
        } else {
            JSONObject data = jsonObject.getJSONObject("data");
            String planId = data.getString("planId");
            String bizNo = data.getString("bizNo");
            fuluUploadPlan.setBizNo(bizNo);
            fuluUploadPlan.setPlanId(planId);
            save(fuluUploadPlan);
            return fuluUploadPlan;
        }
    }

    @Override
    public String queryPlan(FuluUploadPlan fuluUploadPlan) {
        FuluUploadPlan one = lambdaQuery().eq(FuluUploadPlan::getOutBizNo, fuluUploadPlan.getOutBizNo()).one();
        if (one == null) {
            throw new ServiceException("没有此订单!");
        }
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("outBizNo",fuluUploadPlan.getOutBizNo());
        String param = paramPackage(paramsMap);
        String res = null;
        try {
            res = HttpRequestUtils.sendPost(fuluConfig.getAddress() + fuluConfig.getQueryPlan(), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        Integer code = jsonObject.getInteger("code");
        if (code != 0) {
            throw new ServiceException(jsonObject.getString("msg"));
        } else {
            JSONObject data = jsonObject.getJSONObject("data");
            updatePlan(data,one);
        }
        return res;
    }

    @Override
    public void uploadEvidence(CmccDaOrder cmccDaOrder) {
        FuluUploadPeople fuluUploadPeople = fuluUploadPeopleService.lambdaQuery().eq(FuluUploadPeople::getUserId, cmccDaOrder.getUserId()).eq(FuluUploadPeople::getDeleteFlag, 0).one();
        if (fuluUploadPeople == null && "3".equals(String.valueOf(fuluUploadPeople.getSignStatus()))) {
            throw new ServiceException("没有认证，请先认证!");
        }
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        paramsMap.put("taskId",fuluConfig.getTaskNo());
        HashMap<String, Object> evidenceMap = new HashMap<>(16);
        evidenceMap.put("orderTime",cmccDaOrder.getUpdateTime());
        evidenceMap.put("userName", fuluUploadPeople.getUserName());
        evidenceMap.put("orderAmount", cmccDaOrder.getCommission());
        evidenceMap.put("orderNo", cmccDaOrder.getOrderId());
        // 单条证据详情
        String evidenceJsonStr = new Gson().toJson(evidenceMap);
        // 外层关联业务内容
        Map<String, Object> cloMap = new HashMap<>();
        cloMap.put("bizNo", generate32BitUUID());
        cloMap.put("idCard", fuluUploadPeople.getIdCard());
        Date date = Date.from(cmccDaOrder.getUpdateTime().atZone(ZoneId.systemDefault()).toInstant());
        cloMap.put("dataTime", DateUtil.dateToStr(date,null));
        cloMap.put("evidence",evidenceJsonStr);
        paramsMap.put("evidences", Collections.singletonList(cloMap));
        String param = paramPackage(paramsMap);
        String res = null;
        try {
            res = HttpRequestUtils.sendPost(fuluConfig.getAddress() + fuluConfig.getUploadEvidence(), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        FuluUploadEvidence fuluUploadEvidence = new FuluUploadEvidence();
        fuluUploadEvidence.setBizNo(cloMap.get("bizNo").toString());
        fuluUploadEvidence.setOrderNo(cmccDaOrder.getOrderId());
        fuluUploadEvidence.setTaskId(fuluConfig.getTaskNo());
        fuluUploadEvidence.setResponse(res);
        fuluUploadEvidence.setIdCard(fuluUploadPeople.getIdCard());
        fuluUploadEvidence.setEvidence(evidenceJsonStr);
//        fuluUploadEvidence.setPlanId("");
//        fuluUploadEvidence.setDataTime();
        fuluUploadEvidenceService.save(fuluUploadEvidence);
        JSONObject jsonObject = JSONObject.parseObject(res);
        Integer code = jsonObject.getInteger("code");
        if (code == 0) {
            cmccDaOrder.setFuluUploadStatus(1);
            cmccDaOrderService.updateById(cmccDaOrder);
        }
    }



    @Override
    public void fuluMessage(JSONObject jsonObject) {
        JSONObject bizContent = jsonObject.getJSONObject("bizContent");
        String bizOutNo = bizContent.getString("bizOutNo");
        FuluUploadPlan one = lambdaQuery().eq(FuluUploadPlan::getOutBizNo, bizOutNo).one();
        if (one == null) {
            throw new ServiceException("没有此订单!");
        }
        updatePlan(bizContent,one);
    }


    /**
     * 更新工作计划状态
     * @param jsonObject
     * @param one
     */
    public void updatePlan(JSONObject jsonObject,FuluUploadPlan one) {
        FuluUploadPlan fuluUploadPlan1 = JSONObject.toJavaObject(jsonObject, FuluUploadPlan.class);
        fuluUploadPlan1.setId(one.getId());
        fuluUploadPlan1.setOutBizNo(one.getOutBizNo());
        fuluUploadPlan1.setIdCard(one.getIdCard());
        fuluUploadPlan1.setMobile(one.getMobile());
        updateById(fuluUploadPlan1);
        // 查询
        CmccDaCommissionReflection cmccDaCommissionReflection = cmccDaCommissionReflectionService.lambdaQuery().eq(CmccDaCommissionReflection::getOutBizNo, fuluUploadPlan1.getOutBizNo()).one();
        if (cmccDaCommissionReflection != null) {
            SysUser sysUser = sysUserMapper.selectUserById(cmccDaCommissionReflection.getCreateUserId().longValue());
            if (cmccDaCommissionReflection.getReflectionState() == 2 || cmccDaCommissionReflection.getPayStatus() == 4 || cmccDaCommissionReflection.getPayStatus() == 3) {
                return;
            }
            if (cmccDaCommissionReflection.getReflectionState() == 1 && cmccDaCommissionReflection.getPayStatus() == 1) {
                if (fuluUploadPlan1.getAuditStatus() == 2 || fuluUploadPlan1.getAuditStatus() == 3 || fuluUploadPlan1.getGrantStatus() == 2) {
                    cmccDaCommissionReflection.setReflectionState(2);
                    cmccDaCommissionReflection.setReflectionStateDesc("驳回");
                    cmccDaCommissionReflection.setPayStatus(4);
                    cmccDaCommissionReflection.setPayStatusDesc("打款失败");
                    cmccDaCommissionReflection.setRemark(fuluUploadPlan1.getFailCause());
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                    sysUser.setUpdateTime(new Date());
                    sysUser.setCommission(sysUser.getCommission().add(cmccDaCommissionReflection.getReflectionAmount()));
                }  else if (fuluUploadPlan1.getAuditStatus() == 1 && fuluUploadPlan1.getGrantStatus() == 1 && fuluUploadPlan1.getPayStatus() == 3) {
                    cmccDaCommissionReflection.setReflectionState(3);
                    cmccDaCommissionReflection.setReflectionStateDesc("审核通过");
                    cmccDaCommissionReflection.setPayStatus(3);
                    cmccDaCommissionReflection.setPayStatusDesc("打款成功");
                    cmccDaCommissionReflection.setPaymentDate(fuluUploadPlan1.getGrantTime());
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                } else if (fuluUploadPlan1.getAuditStatus() == 1 && fuluUploadPlan1.getGrantStatus() == 1 && (fuluUploadPlan1.getPayStatus() == 4 || fuluUploadPlan1.getPayStatus() == 5)) {
                    cmccDaCommissionReflection.setReflectionState(3);
                    cmccDaCommissionReflection.setReflectionStateDesc("审核通过");
                    cmccDaCommissionReflection.setPayStatus(4);
                    cmccDaCommissionReflection.setPayStatusDesc("打款失败");
                    cmccDaCommissionReflection.setRemark(fuluUploadPlan1.getPayFailCause());
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                    sysUser.setUpdateTime(new Date());
                    sysUser.setCommission(sysUser.getCommission().add(cmccDaCommissionReflection.getReflectionAmount()));
                } else if (fuluUploadPlan1.getAuditStatus() == 1 && fuluUploadPlan1.getGrantStatus() == 1) {
                    cmccDaCommissionReflection.setReflectionState(3);
                    cmccDaCommissionReflection.setReflectionStateDesc("审核通过");
                    cmccDaCommissionReflection.setPayStatus(2);
                    cmccDaCommissionReflection.setPayStatusDesc("打款中");
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                }
            } else if (cmccDaCommissionReflection.getReflectionState() == 3 && (cmccDaCommissionReflection.getPayStatus() == 1 ||cmccDaCommissionReflection.getPayStatus() == 2)) {
                if (fuluUploadPlan1.getPayStatus() == 4 || fuluUploadPlan1.getPayStatus() == 5) {
                    cmccDaCommissionReflection.setPayStatus(4);
                    cmccDaCommissionReflection.setPayStatusDesc("打款失败");
                    cmccDaCommissionReflection.setRemark(fuluUploadPlan1.getPayFailCause());
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                    sysUser.setUpdateTime(new Date());
                    sysUser.setCommission(sysUser.getCommission().add(cmccDaCommissionReflection.getReflectionAmount()));
                } else if (fuluUploadPlan1.getPayStatus() == 3) {
                    cmccDaCommissionReflection.setPayStatus(3);
                    cmccDaCommissionReflection.setPayStatusDesc("打款成功");
                    cmccDaCommissionReflection.setPaymentDate(fuluUploadPlan1.getGrantTime());
                    cmccDaCommissionReflection.setUpdateTime(new Date());
                }
            }
            sysUserMapper.updateUser(sysUser);
            cmccDaCommissionReflectionService.updateById(cmccDaCommissionReflection);
        }
    }



    public String paramPackage(Map<String, Object> paramsMap) {
        String json = new Gson().toJson(paramsMap);
        long time = System.currentTimeMillis();
        String currentTimeMillis = String.valueOf(time);
        // 长度最大32位
        String nonce = generate32BitUUID();
        // 固定参数
        Map<String, String> param = new HashMap<>();
        param.put("appId", fuluConfig.getAppId());
        param.put("nonce", nonce);
        param.put("timestamp", currentTimeMillis);
        param.put("bizContent", json);
        String sign = null;
        String sortParams = sortParams(param);
        //System.out.println("排序字段:" + sortParams);
        String sb = splice(fuluConfig.getAppSecret(), sortParams);
        //System.out.println("加签名字符串排序字段 :" + sb);
        try {
            sign = sign(sb, currentTimeMillis, fuluConfig.getAppSecret());
        } catch (Exception e) {
            e.printStackTrace();
        }
        param.put("sign", sign);
        System.out.println("签名 : " + sign);
        String postJson = new Gson().toJson(param);
        return postJson;

    }


    public static String generate32BitUUID() {
        UUID uuid = UUID.randomUUID();
        String uuidString = uuid.toString();
        // 去掉'-'分隔符
        String uuid32Bit = uuidString.replace("-", "");
        return uuid32Bit;
    }
    /**
     * 将map排序为字符串
     * @param parameters
     * @return
     */
    public static String sortParams(Map<String, String> parameters) {

        if (parameters.isEmpty()) {
            return null;
        }
        List<String> removeKeys = new ArrayList<>();
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            if (isBlank(entry.getValue())) {
                removeKeys.add(entry.getKey());
            }
        }

        for (String key : removeKeys) {
            parameters.remove(key);
        }
        StringBuilder stringBuilder = new StringBuilder();
        SortedMap<String, String> paramMap = new TreeMap<>(parameters);
        int index = 0;
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            stringBuilder.append(entry.getKey()).append("=").append(entry.getValue());
            index++;
            if (index != parameters.size()) {
                stringBuilder.append("&");
            }
        }
        return stringBuilder.toString();
    }


    public static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
    }

    public static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

    /**
     * 拼接appSecret和
     * @param appSecret
     * @param content sortParams
     * @return
     */
    public static String splice(String appSecret, String content) {

        if (appSecret == null ) {
            return content;
        }
        if (appSecret.length() < 10){
            return "";
        }

        // 截取前5位和后5位
        String front = appSecret.substring(0, 5);
        String back = appSecret.substring(appSecret.length() - 5);

        return front + content + back;
    }


    /**
     * @param sortParam 排序map后得到的字符串
     * @param timestamp 时间戳
     * @param appSecret 应用秘钥
     * @return 签名值
     * @throws Exception 异常
     */
    public static String sign(String sortParam,
                              String timestamp,
                              String appSecret) throws Exception {
        //将排序后字符串转为sha256Hex
        String signText = sha256Hex(sortParam);
        System.out.println(signText);
        //计算签名
        byte[] secretSigning = hmac256((appSecret).getBytes(StandardCharsets.UTF_8), timestamp);
        //计算后得到签名
        return DatatypeConverter.printHexBinary(hmac256(secretSigning, signText)).toLowerCase();
    }

    public static boolean isBlank(CharSequence str) {
        int length;

        if ((str == null) || ((length = str.length()) == 0)) {
            return true;
        }

        for (int i = 0; i < length; i++) {
            // 只要有一个非空字符即为非空字符串
            if (false == isBlankChar(str.charAt(i))) {
                return false;
            }
        }

        return true;
    }

    public static boolean isBlankChar(int c) {
        return Character.isWhitespace(c)
                || Character.isSpaceChar(c)
                || c == '\ufeff'
                || c == '\u202a'
                || c == '\u0000';
    }


}
